/** ***********************************************************************************
* @file         usb_task.c
* @brief        USB数据处理任务
* @details      处于用来处理USB底层数据接收/发送等操作
* @author       杨小珛
* @date         2021/2/18
* @copyright    北京高知科技有限公司    
* @version      V1.0
* @attention    无
**************************************************************************************/

#include "usb_task.h"
#include "mon_task.h"
#include "log_task.h"
#include "power_task.h"
#include "com_lib.h"

#define USB_RECV_NAME   "USB_RECV_TASK"
GaozMutexHandle_t usb_data_recv_mutex;   /*定义接口互斥体*/
GaozMutexHandle_t usb_data_send_mutex;   /*定义接口互斥体*/
GaozQueueHandle_t usb_data_recv_queue;   /*定义USB数据接收消息队列*/
GaozSemaphoreHandle_t usb_data_recv_semaphore; /*USB数据信号量*/
usb_recv_buf_typedef usb_recv_buf_t;      /*USB底层数据接收结构体*/
atDevice_t *usb_th;

static void usb_data_update_buf(uint8_t *buf, uint16_t len);
static void  usb_recv_data_handle_task( void * pvParameters);
static void  usb_data_recv_queue_create(void);
static uint32_t usb_data_recv_queue_get(usb_recv_buf_typedef *msg , uint32_t time );


/** ****************************************************************************
* @remarks       static void  usb_hal_recv_cb(atDevice_t *th, void *buf, size_t size, void *arg)
* @brief         USB数据回调函数
* @param[in]     无
* @param[out]    *th USB ID
* @param[out]    *buf 数据地址
* @param[out]    size 数据长度
* @param[out]    *arg 系统参数
* @return        无
* @attention     无
*******************************************************************************/
static void  usb_hal_recv_cb(atDevice_t *th, void *buf, size_t size, void *arg)
{   
    usb_data_update_buf( buf, size );
    gaoz_sem_signal( usb_data_recv_semaphore ); /*发送信号量，通知任务*/
}   

/** ****************************************************************************
* @remarks       static void usb_data_update_buf(uint8_t *buf, uint16_t len)
* @brief         USB数据更新
* @param[in]     *buf 数据源地址
* @param[in]     len 数据长度
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void usb_data_update_buf(uint8_t *buf, uint16_t len)
{
    gaoz_mutex_lock( usb_data_recv_mutex );
    if( len > USB_DATA_RECV_BUF_SIZE ) /*内存边界判断*/
    {
        len = USB_DATA_RECV_BUF_SIZE; 
    }
    memcpy((uint8_t *)usb_recv_buf_t.data ,(uint8_t *)buf , len  );
    usb_recv_buf_t.len = len;
    gaoz_mutex_unlock( usb_data_recv_mutex );
}

/** ****************************************************************************
* @remarks       void usb_create_task( unsigned portBASE_TYPE uxPriority )
* @brief         创建USB基层数据处理任务
* @param[in]     uxPriority 优先级
* @param[out]    无
* @return        无
* @attention     在系统启动后进行创建
*******************************************************************************/
void usb_create_task( unsigned portBASE_TYPE uxPriority )
{
    usb_th = gaoz_usb_device_init( DRV_NAME_USRL_COM6, usb_hal_recv_cb ); /*初始化USB底层数据接收*/
    if( usb_th == NULL )
    {
         while( 1 ); /*创建失败*/
    }
    /*创建USB数串口数据接收空间*/
    usb_recv_buf_t.data  = (uint8_t *)gaoz_fibo_malloc( USB_DATA_RECV_BUF_SIZE + 10 );
    if( usb_recv_buf_t.data == NULL )
    {
        while(1); /*创建失败*/
    }
    memset((uint8_t *)usb_recv_buf_t.data, 0x00 , USB_DATA_RECV_BUF_SIZE + 10);
    usb_recv_buf_t.len = 0;

    
    usb_data_recv_mutex = gaoz_mutex_create(); /*创建USB 数据接收互斥体*/
    if( usb_data_recv_mutex == 0 )
    {
        while( 1 ); /*创建失败*/
    }
    
    usb_data_send_mutex = gaoz_mutex_create(); /*创建USB 数据发送互斥体*/
    if( usb_data_send_mutex == 0 )
    {
        while( 1 ); /*创建失败*/
    }
    usb_data_recv_semaphore = gaoz_sem_new(0);
    if( usb_data_recv_semaphore == 0 )
    {
        while( 1 ); /*创建失败*/
    }
    usb_data_recv_queue_create();
    gaoz_thread_create(usb_recv_data_handle_task, USB_RECV_NAME, 1024*2, NULL, uxPriority);
}

/** ****************************************************************************
* @remarks       static uint8_t usb_data_recv_sam_get(void)
* @brief         获取USB底层接收数据的信号量
* @param[in]     无
* @param[out]    无
* @return        1 接收到数据 ， 0 未接收到数据，超时
* @attention     阻塞状态 时间3s USB_DATA_RECV_WAIT_TIME
*******************************************************************************/
static uint8_t usb_data_recv_sam_get(void)
{
    if( gaoz_sem_try_wait( usb_data_recv_semaphore, USB_DATA_RECV_WAIT_TIME ) == true ) //等待回应信号量
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/** ****************************************************************************
* @remarks       static void usb_data_recv_queue_create(void)
* @brief         创建USB数据接收消息队列
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void  usb_data_recv_queue_create(void)
{
    usb_data_recv_queue = gaoz_queue_create(USB_DATA_RECV_QUEUE_MAX_NUM, sizeof(usb_recv_buf_typedef));
    if(usb_data_recv_queue == 0)
    {
        while(1); /*创建消息队列失败*/
    }
}

/** ****************************************************************************
* @remarks       static uint32_t usb_data_recv_queue_get(usb_recv_buf_typedef *msg , uint32_t time )
* @brief         获取USB接收数据消息队列数据
* @param[in]     time 信息阻塞时间 单位 ms
* @param[out]    *msg 消息队列目标地址
* @return        pdPASS 获取数据成功 ， pdFAIL 获取数据失败
* @attention     无
*******************************************************************************/
static uint32_t usb_data_recv_queue_get(usb_recv_buf_typedef *msg , uint32_t time )
{
    if(usb_data_recv_queue == 0)
    {
        usb_data_recv_queue_create(); 
    }
    if( gaoz_queue_get( usb_data_recv_queue, msg, time ) == 0 )
    {
        return pdPASS;
    }
    else
    {
        return pdFAIL;
    }
}

/** ****************************************************************************
* @remarks       uint32_t usb_driver_recv_data( uint8_t *data , uint16_t *len , uint32_t time)
* @brief         USB底层发送数据
* @param[in]     time 读取数据阻塞的时间 单位ms
* @param[out]    *data 目标地址
* @param[out]    *len 数据长度
* @return        pdPASS 接收数据成功 ， pdFAIL 接收数据失败
* @attention     可以通过设置时间选择阻塞的时间长度，为0时一直阻塞
*******************************************************************************/
uint32_t usb_driver_recv_data( uint8_t *data , uint16_t *len , uint32_t time)
{
    uint32_t ret = pdFAIL;
    usb_recv_buf_typedef recv_msg;
    if(( data == NULL ) || ( len == NULL ))
    {
        return ret;
    }
    if( usb_data_recv_queue_get( &recv_msg , time ) == pdPASS )
    {
        memcpy((uint8_t *)data , (uint8_t *)recv_msg.data ,recv_msg.len);
        *len = recv_msg.len;
        gaoz_free_mem(( void * )recv_msg.data ); /*释放系统空间*/
        ret = pdPASS;
    }
    return ret;
}

/** ****************************************************************************
* @remarks       uint32_t usb_data_recv_sam_get( uint8_t *data , uint16_t len )
* @brief         USB底层发送数据
* @param[in]     *data 发送数据的源地址
* @param[in]     len 发送数据的长度
* @param[out]    无
* @return        pdPASS 发送数据成功 ， pdFAIL 发送数据失败
* @attention     带有互锁机制，支持多任务使用；
*******************************************************************************/
uint32_t usb_driver_send_data( uint8_t *data , uint16_t len )
{
    uint32_t ret = pdPASS;
    
    if(( usb_th == NULL ) || ( data == 0 ))
    {
        return pdFAIL;
    }
    gaoz_mutex_lock( usb_data_send_mutex ); 
    if( gaoz_usb_device_send(usb_th,( const uint8_t * )data, len) < 0 )
    {
        ret = pdFAIL;
    }
    gaoz_mutex_unlock( usb_data_send_mutex );
    return ret;
}

/** ****************************************************************************
* @remarks       static void  usb_recv_data_handle_task( void * pvParameters)
* @brief         处理USB接收的底层数据处理任务，接收数据任务。
* @param[in]     * pvParameters 任务参数
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void  usb_recv_data_handle_task( void * pvParameters)
{ 
    volatile    uint8_t *pbuf = NULL;
    usb_recv_buf_typedef recv_data;
    mon_reg_task_dog( 60 * GAOZ_TICK_PERIOD_S ,(uint8_t * )USB_RECV_NAME , TASK_SEM_YES );
    log_debug_send(DEBUG_MODE,USB_RECV_NAME ,"USB revc data task started successfully\r\n",0);
    for( ;; )
    {
        mon_reset_task_dog();
        
        if( usb_data_recv_sam_get() == 1 ) /*接收数据信号量*/
        {
            /***********************互斥机制，快速处理底层数据******************************************/
            gaoz_mutex_lock( usb_data_recv_mutex ); 
            pbuf = gaoz_malloc_mem( usb_recv_buf_t.len  + 8 ); /*动态申请空间，空间位置处于FreeRtos总栈空间中*/
            if( pbuf == NULL )
            {
                log_debug_printf(ERROR_MODE,USB_RECV_NAME ,"[%s]Dynamic allocation of application space failed!\r\n",sys_err_infor_pointer_get( 19 ));
                gaoz_mutex_unlock( usb_data_recv_mutex );
                continue;
            }
            memcpy(( uint8_t * )pbuf, ( uint8_t * )usb_recv_buf_t.data, usb_recv_buf_t.len ); 
            recv_data.data = ( uint8_t * )pbuf;
            recv_data.len = usb_recv_buf_t.len;
            memset(( uint8_t * )usb_recv_buf_t.data, 0x00, USB_DATA_RECV_BUF_SIZE );
            usb_recv_buf_t.len = 0x00;
            gaoz_mutex_unlock( usb_data_recv_mutex );
            /*******************************************************************************************/
            log_debug_send( INFOR_MODE,USB_RECV_NAME ,(uint8_t *)recv_data.data, recv_data.len );
            if( gaoz_queue_put( usb_data_recv_queue, ( void * )&recv_data, 1000 ) < 0 )
            {
                gaoz_free_mem(( void * )recv_data.data ); /*释放系统空间*/
                log_debug_printf(ERROR_MODE,USB_RECV_NAME ,"[%s]USB data recv queue is full!\r\n",sys_err_infor_pointer_get( 20 ));
                continue;
            }
        }
    }
}

